local ffi = require "ffi"
local lib_Http = require "gamesense/http" or error("Sub https://gamesense.pub/forums/viewtopic.php?id=19253")
local lib_Md5 = require "gamesense/md5" or error("Sub md5 Error")
local lib_Base64 = require 'gamesense/base64' or error("Sub base32 Error")

--[[ 优先Hook LuaTable 防止被HookLoad ]]
local c_tostring = _G["tostring"]
local c_loadstring = _G["loadstring"]


--[[ 定义用户Token 一次性]]
local userToken = "<spring#userToken#>"


--[[ 定义云载服务器地址 基于SpringCloud架构每次随机选择服务器 用于负载均衡 ]]
local AegisCloudServerList = {
    "http://127.0.0.1:2333",
    "http://192.168.55.5:2333",
    "http://aegis.xiaozhengkeji.com:2333",
}


--[[ 定义云载相关参数 ]]
local AegisCloudBase = {
    --[[ 云载验证错误次数  用于网络异常冗余 ]]
    VerifyError = 0,
    --[[ 用户HWID ]]
    UserHWID = "",
    --[[ 用户载入令牌 ]]
    LoadToken = "",
    --[[ 随机选择服务器 math.random(1,#AegisCloudServerList)]]
    ApiBase = AegisCloudServerList[1],
}

local function log(log)
    client.color_log(0, 125, 255, "[AegisCloud]: " .. log)
end

log("Server Size: " .. #AegisCloudServerList .. " ")

local function getHWID()
    local def = ffi.cdef([[
    typedef struct MaterialAdapterInfo_t {
            char m_pDriverName[512];
            unsigned int m_VendorID;
            unsigned int m_DeviceID;
            unsigned int m_SubSysID;
            unsigned int m_Revision;
            int m_nDXSupportLevel;
            int m_nMinDXSupportLevel;
            int m_nMaxDXSupportLevel;
            unsigned int m_nDriverVersionHigh;
            unsigned int m_nDriverVersionLow;
    };

    typedef int(__thiscall* get_current_adapter_fn)(void*);
    typedef void(__thiscall* get_adapter_info_fn)(void*, int adapter, struct MaterialAdapterInfo_t& info);
    ]]
    )
    local material_system = client.create_interface('materialsystem.dll', 'VMaterialSystem080')
    local material_interface = ffi.cast('void***', material_system)[0]
    local get_current_adapter = ffi.cast('get_current_adapter_fn', material_interface[25])
    local get_adapter_info = ffi.cast('get_adapter_info_fn', material_interface[26])
    local current_adapter = get_current_adapter(material_interface)
    local adapter_struct = ffi.new('struct MaterialAdapterInfo_t')
    get_adapter_info(material_interface, current_adapter, adapter_struct)
    local driverName = c_tostring(ffi.string(adapter_struct['m_pDriverName']))
    local vendorId = c_tostring(adapter_struct['m_VendorID'])
    local deviceId = c_tostring(adapter_struct['m_DeviceID'])
    return lib_Md5.sumhexa(driverName .. " aegis") .. " "
end

--[[ 获取用户的HWID ]]
AegisCloudBase.UserHWID = getHWID()

log("User HWID: " .. AegisCloudBase.UserHWID)


--[[ 定义自写加密 ]]
local xiaozheng = {}

xiaozheng.__code = {
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
    'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
};
xiaozheng.__decode = {}
for k, v in pairs(xiaozheng.__code) do
    xiaozheng.__decode[string.byte(v, 1)] = k - 1
end

function xiaozheng.encode(text)
    local len = string.len(text)
    local left = len % 3
    len = len - left
    local res = {}
    local index = 1
    for i = 1, len, 3 do
        local a = string.byte(text, i)
        local b = string.byte(text, i + 1)
        local c = string.byte(text, i + 2)
        local num = a * 65536 + b * 256 + c
        for j = 1, 4 do
            local tmp = math.floor(num / (2 ^ ((4 - j) * 6)))
            local curPos = tmp % 64 + 1
            res[index] = xiaozheng.__code[curPos]
            index = index + 1
        end
    end

    if left == 1 then
        xiaozheng.__left1(res, index, text, len)
    elseif left == 2 then
        xiaozheng.__left2(res, index, text, len)
    end
    return table.concat(res)
end

function xiaozheng.__left2(res, index, text, len)
    local num1 = string.byte(text, len + 1)
    num1 = num1 * 1024
    local num2 = string.byte(text, len + 2)
    num2 = num2 * 4
    local num = num1 + num2

    local tmp1 = math.floor(num / 4096)
    local curPos = tmp1 % 64 + 1
    res[index] = xiaozheng.__code[curPos]

    local tmp2 = math.floor(num / 64)
    curPos = tmp2 % 64 + 1
    res[index + 1] = xiaozheng.__code[curPos]

    curPos = num % 64 + 1
    res[index + 2] = xiaozheng.__code[curPos]

    res[index + 3] = "="
end

function xiaozheng.__left1(res, index, text, len)
    local num = string.byte(text, len + 1)
    num = num * 16

    tmp = math.floor(num / 64)
    local curPos = tmp % 64 + 1
    res[index] = xiaozheng.__code[curPos]

    curPos = num % 64 + 1
    res[index + 1] = xiaozheng.__code[curPos]

    res[index + 2] = "="
    res[index + 3] = "="
end

function xiaozheng.decode(text)
    local len = string.len(text)
    local left = 0
    if string.sub(text, len - 1) == "==" then
        left = 2
        len = len - 4
    elseif string.sub(text, len) == "=" then
        left = 1
        len = len - 4
    end

    local res = {}
    local index = 1
    local decode = xiaozheng.__decode
    for i = 1, len, 4 do
        local a = decode[string.byte(text, i)]
        local b = decode[string.byte(text, i + 1)]
        local c = decode[string.byte(text, i + 2)]
        local d = decode[string.byte(text, i + 3)]
        --[[ cc<< ]]
        local num = a * 262144 + b * 4096 + c * 64 + d

        local e = string.char(num % 256)
        num = math.floor(num / 256)
        local f = string.char(num % 256)
        num = math.floor(num / 256)
        res[index] = string.char(num % 256)
        res[index + 1] = f
        res[index + 2] = e
        index = index + 3
    end

    if left == 1 then
        xiaozheng.__decodeLeft1(res, index, text, len)
    elseif left == 2 then
        xiaozheng.__decodeLeft2(res, index, text, len)
    end
    return table.concat(res)
end

function xiaozheng.__decodeLeft1(res, index, text, len)
    local decode = xiaozheng.__decode
    local a = decode[string.byte(text, len + 1)]
    local b = decode[string.byte(text, len + 2)]
    local c = decode[string.byte(text, len + 3)]
    local num = a * 4096 + b * 64 + c
    local num1 = math.floor(num / 1024) % 256
    local num2 = math.floor(num / 4) % 256
    res[index] = string.char(num1)
    res[index + 1] = string.char(num2)
end

function xiaozheng.__decodeLeft2(res, index, text, len)
    local decode = xiaozheng.__decode
    local a = decode[string.byte(text, len + 1)]
    local b = decode[string.byte(text, len + 2)]
    local num = a * 64 + b
    num = math.floor(num / 16)
    res[index] = string.char(num)
end

function xiaozheng.xdecode(str)
    str = string.gsub(str, "<", "A")
    str = string.gsub(str, ">", "C")
    str = string.gsub(str, "&", "B")
    str = string.gsub(str, "#", "D")
    str = string.gsub(str, "@", "=")
    str = string.gsub(str, "?", "j")
    str = string.gsub(str, "*", "g")
    str = string.gsub(str, "-", "W")
    str = string.gsub(str, "{", "6")
    str = string.gsub(str, "}", "Z")
    str = string.gsub(str, "!", "4")
    return str
end

local loadList = {}

--[[ 第二次网络验证 进行load ]]
local function loadInit()
    --[[ 对loadList进行遍历 进行Lua分段加载 ]]
    for i = 1, #loadList do
        local tags = loadList[i]
        lib_Http.post(AegisCloudBase.ApiBase .. "/cloud/v1/gamesense/load", { params = { userToken = userToken, userHWID = AegisCloudBase.UserHWID, tags = tags , loadToken = AegisCloudBase.LoadToken } }, function(success, data)
            if data.status == 200 then
                --[[ 对返回的JSON数据进行Object ]]
                local temp = json.parse(data.body)
                if temp.code == 200 then
                    log("load " .. temp.msg)
                    --[[ 在正式版本中会进行3次解密和1次自写算法解密 ]]
                    local temp_lua = xiaozheng.decode(temp.data)
                    c_loadstring(temp_lua)
                    log("load " .. temp.msg .. " succeed")
                else
                    --[[ 返回服务器返回的错误信息 ]]
                    log(temp.msg)
                end
            else
                --[[ 无法连接到服务器 ]]
                log("Net Error")
            end
        end)
    end

    log("load Succeed")
end
--[[ 进行第一次网络验证 ]]
log("Please wait. The server is being connected")
--[[ 初始验证 并且拿到Lua Load Table ]]
--[[ 每分钟只能加载1次 ]]
lib_Http.post(AegisCloudBase.ApiBase .. "/cloud/v1/gamesense/toverify", { params = { userToken = userToken, userHWID = AegisCloudBase.UserHWID } }, function(success, data)
    if data.status == 200 then
        --[[ 对返回的JSON数据进行Object ]]
        local temp = json.parse(data.body)
        if temp.code == 200 then
            AegisCloudBase.VerifyError = 0
            --[[ 进行登录成功后的调用 ]]
            log(temp.msg) --[[ 登录成功后会返回  欢迎! <username> ]]
            log("Loading for you, Please wait!")
            --[[ 对返回的数据进行整理 ]]
            loadList = temp.data
            AegisCloudBase.LoadToken = temp.data_standby
            loadInit()
        else
            --[[ 返回服务器返回的错误信息 ]]
            log(temp.msg)
        end
    else
        --[[ 无法连接到服务器 ]]
        log("Net Error")
    end

end)
